#pragma once
#include <iostream>
#include <memory>
#include <set>

#include "epoller.hpp"
#include "Socket.hpp"
#include "Log.hpp"

const static int maxevents = 20;

class Epoll
{
public:
    Epoll(uint16_t port)
        : _server(new TCP_Server_Socket(port))
        , _epoller(new Epoller())
        , _maxevents(maxevents)
        , _epevent(new epoll_event[_maxevents])
    {
        // 初始化server端，完成监听
        _server->ServerInit();
        // 将listen_fd设置到内核中，让其关心EPOLLIN事件
        _epoller->AddEvent(_server->GetListenfd());
        _fds.insert(_server->GetListenfd());
    }

    ~Epoll()
    {
        delete[] _epevent;
    }

    void Loop()
    {
        while (true)
        {
            PrintDebug();
            int ret = _epoller->Wait(_epevent, _maxevents);

            // 在timeout内，有事件就绪，ret表示真正拿到的就绪事件的fd个数
            if (ret > 0)
            {
                // 处理事件
                Handler(ret);
            }
            // 无事件就绪
            else if (ret == 0)
            {
                std::cout << "没有事件就绪" << std::endl;
            }
            // 等待fd的事件时出错
            else
            {
                _log.LogMessage(ClassFile, Error, "wait error\n");
            }

        }
    }

private:
    // 已有就绪事件，处理事件
    void Handler(int size)
    {
        for(int i = 0; i < size; ++i)
        {
            int fd = _epevent[i].data.fd;
            // 读事件就绪
            if(_epevent[i].events & EPOLLIN)
            {
                // accept条件就绪
                if(fd == _server->GetListenfd())
                {
                    std::cout << "accept就绪" << std::endl;
                    _server->Accept();
                    _epoller->AddEvent(_server->Getfd());
                    _fds.insert(_server->Getfd());
                }
                // 读事件就绪
                else
                {
                    std::cout << "recv就绪" << std::endl;
                    bool ret = _server->Recv(fd);
                    // 读取失败 / 对端关闭
                    if(!ret) 
                    {
                        // 删除对该fd的关心
                        _epoller->DelEvent(fd);
                        close(fd);
                        _fds.erase(fd);
                    }
                }
            }
        }
    }
    void PrintDebug()
    {
        std::cout << "当前打开的fd : ";
        for(auto& e : _fds)
        {
            std::cout << e << " ";
        }
        std::cout << std::endl;
    }
private:
    std::unique_ptr<Socket> _server;
    std::unique_ptr<Epoller> _epoller;
    int _maxevents;        // 用户层一次拿多少个就绪事件fd  
    epoll_event *_epevent; // 用于拿到就绪事件的fd
    std::set<int> _fds;
};
